package cn.mw.cmdb.exception;

import cn.mw.components.mongodb.exception.BusinessException;
import cn.mw.microMonitorCommon.api.common.BaseApiService;
import cn.mw.microMonitorCommon.api.common.ResponseBase;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileUploadBase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MultipartException;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler extends BaseApiService {

    @Autowired
    private MessageSource messageSource;
    @Value("${spring.servlet.multipart.max-file-size}")
    private String maxFileSize;

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseBase handleException(Exception e) {
        log.error("internal exception:", e);
        return setResultFail();
    }

    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public ResponseBase handleBusinessException(BusinessException e) {
        String key = e.getMessageKey();
        String message = messageSource.getMessage(key, e.getArgs(), LocaleContextHolder.getLocale());
        return setResultFail(message);
    }

    @ExceptionHandler(CompoundException.class)
    @ResponseBody
    public ResponseBase handleBusinessException(CompoundException e) {
        StringBuffer sb = new StringBuffer(messageSource.getMessage(e.getMessageKey(), e.getArgs(), LocaleContextHolder.getLocale()));
        sb.append("[");
        for (BusinessException b : e.getExceptionList()) {
            sb.append(messageSource.getMessage(b.getMessageKey(), b.getArgs(), LocaleContextHolder.getLocale())).append(";");
        }
        sb.append("]");
        return setResultFail(sb.toString());
    }

    /**
     * 参数校验不通过
     *
     * @param e BindException
     * @return ResultVo<Void>
     */
    @ExceptionHandler(BindException.class)
    public ResponseBase handlerBindException(BindException e) {
        return setResultFail(this.buildMsg(e.getBindingResult()));
    }

    /**
     * 参数校验不通过
     *
     * @param e MethodArgumentNotValidException
     * @return ResultVo<Void>
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseBase handlerMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        return setResultFail(buildMsg(e.getBindingResult()));
    }

    /**
     * 构建参数错误提示信息
     *
     * @param bindingResult BindingResult
     * @return String
     */
    private String buildMsg(BindingResult bindingResult) {
        StringBuilder builder = new StringBuilder(32);
        for (FieldError error : bindingResult.getFieldErrors()) {
            builder.append(", [").append(error.getField()).append(":").append(error.getDefaultMessage()).append("]");
        }
        return builder.substring(2);
    }


    @ExceptionHandler(MultipartException.class)
    public ResponseBase handleDataIntegrityViolationException(MultipartException exception, HttpServletResponse response) {
        if (exception.getRootCause() instanceof FileUploadBase.FileSizeLimitExceededException) {
            return setResultFail(messageSource.getMessage("maximum-upload-size", new String[]{maxFileSize}, LocaleContextHolder.getLocale()));
        }
        if (exception.getRootCause() instanceof FileUploadBase.SizeLimitExceededException) {
            return setResultFail(messageSource.getMessage("maximum-upload-size", new String[]{maxFileSize}, LocaleContextHolder.getLocale()));
        } else {
            return setResultFail(messageSource.getMessage("upload-file-error", null, LocaleContextHolder.getLocale()));
        }
    }

    @ExceptionHandler(AccessDeniedException.class)
    public ResponseBase handlerAccessDeniedException(AccessDeniedException e) {
        String message = messageSource.getMessage("no_handle_auth", null, LocaleContextHolder.getLocale());
        return setResultFail(message);
    }
}
